﻿using System.Security.Claims;
using System.Text;
using Api.Attributes;
using Microsoft.AspNetCore.Http.Features;

namespace Api.Middleware
{
    /// <summary>
    /// 请求日志
    /// </summary>
    public class RequestLogMiddleware
    {
        #region Ioc
        private readonly RequestDelegate _next;

        public RequestLogMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        #endregion

        #region InvokeAsync
        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                var request = context.Request;
                var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;

                if (endpoint.IsNotEmpty() && endpoint.Metadata.GetMetadata<NotRequestLogAttribute>().IsNotEmpty())
                {
                    //如果有特性，则跳过此中间件
                    await _next(context);
                }
                else if ((request.Path.ToString().ToLower().StartsWith("/upload/") || request.Path.ToString().ToLower().Contains("favicon.ico")) && request.Method.ToLower() == "get")
                {
                    //如果是访问根目录下的Upload文件夹，则跳过此中间件
                    //这里并不是说调用上传接口，而是通过浏览器访问Upload文件夹下的内容
                    await _next(context);
                }
                else
                {
                    //通过request对象获取相关请求信息
                    var url = $"{request.Scheme}://{request.Host.Value}{request.Path}{request.QueryString.Value}";
                    var method = request.Method;
                    var ip = context.Connection.RemoteIpAddress?.ToString();

                    //获取请求体的内容
                    string body = string.Empty;
                    if (request.ContentLength.IsNotEmpty())
                    {
                        request.EnableBuffering();
                        Stream stream = request.Body;
                        var buffer = new byte[request.ContentLength.Value];
                        await stream.ReadAsync(buffer, 0, buffer.Length);
                        request.Body.Position = 0;

                        body = Encoding.UTF8.GetString(buffer);

                        object obj = body.Deserialize<object>();
                        body = obj.Serialize();
                    }

                    //获取登录用户信息
                    string loginTypeCode = context.User.FindFirstValue(Gx._LOGIN_CODE_KEY);
                    string loginTypeID = context.User.FindFirstValue(Gx._LOGIN_TYPE_ID_KEY);
                    string userID = context.User.FindFirstValue(Gx._USERID_KEY);
                    string userName = context.User.FindFirstValue(Gx._USERNAME_KEY);

                    //拼接日志内容
                    StringBuilder sb = new();
                    sb.AppendLine($"【请求Url】：{url}");
                    sb.AppendLine($"【请求类型】：{method}");
                    sb.AppendLine($"【请求参数】：{body}");
                    sb.AppendLine($"【LoginTypeCode / LoginTypeID / UserID / UserName】：{loginTypeCode} / {loginTypeID} / {userID} / {userName}");
                    sb.AppendLine($"【来源IP】：{ip}");

                    Gx.Log(sb.ToString(), "请求日志-");

                    //继续执行其它中间
                    await _next(context);
                }
            }
            catch
            {
                //继续执行其它中间
                await _next(context);
            }
        }
        #endregion
    }

    #region 扩展方法
    public static class RequestLogMiddlewareExt
    {
        public static IApplicationBuilder UseRequestLog(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestLogMiddleware>();
        }
    }
    #endregion
}
